﻿// <copyright file="AddInTokenNonGenericExtensions.cs" company="Anatoly Sereda">
// © 2009 Anatoly Sereda
//
// This source is subject to the Microsoft Public License.
// Please see the License.txt file for more information.
// All other rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// </copyright>
// <author>Anatoly Sereda</author>
// <email>neonnvr@live.com</email>
// <date>2009-08-04</date>

using System;
using System.AddIn.Hosting;
using System.Collections.Generic;
using System.Reflection;
using System.Security;

namespace MafMefInterop.Internal
{
	internal static class AddInTokenNonGenericExtensions
	{
		private static readonly MethodInfo activate1def;
		private static readonly MethodInfo activate2def;
		private static readonly MethodInfo activate3def;
		private static readonly MethodInfo activate4def;
		private static readonly MethodInfo activate5def;
		private static readonly MethodInfo activate6def;
		private static readonly MethodInfo activate7def;

		private static Dictionary<Type, Wrapper> wrappers = new Dictionary<Type, Wrapper>();

		static AddInTokenNonGenericExtensions()
		{
			Type type = typeof(AddInToken);

			string methodName = "Activate";
			activate1def = type.GetMethod(methodName, new[] { typeof(AddInEnvironment) });
			activate2def = type.GetMethod(methodName, new[] { typeof(AddInSecurityLevel) });
			activate3def = type.GetMethod(methodName, new[] { typeof(AppDomain) });
			activate4def = type.GetMethod(methodName, new[] { typeof(PermissionSet) });
			activate5def = type.GetMethod(methodName, new[] { typeof(AddInProcess), typeof(AddInSecurityLevel) });
			activate6def = type.GetMethod(methodName, new[] { typeof(AddInProcess), typeof(PermissionSet) });
			activate7def = type.GetMethod(methodName, new[] { typeof(AddInSecurityLevel), typeof(string) });
		}

		public static object Activate(this AddInToken token, Type hostViewOfContract, AddInEnvironment environment)
		{
			return GetWrapper(hostViewOfContract).Activate(token, environment);
		}

		public static object Activate(this AddInToken token, Type hostViewOfContract, AddInSecurityLevel trustLevel)
		{
			return GetWrapper(hostViewOfContract).Activate(token, trustLevel);
		}

		public static object Activate(this AddInToken token, Type hostViewOfContract, AppDomain target)
		{
			return GetWrapper(hostViewOfContract).Activate(token, target);
		}

		public static object Activate(this AddInToken token, Type hostViewOfContract, PermissionSet permissions)
		{
			return GetWrapper(hostViewOfContract).Activate(token, permissions);
		}

		public static object Activate(this AddInToken token, Type hostViewOfContract, AddInProcess process, AddInSecurityLevel level)
		{
			return GetWrapper(hostViewOfContract).Activate(token, process, level);
		}

		public static object Activate(this AddInToken token, Type hostViewOfContract, AddInProcess process, PermissionSet permissionSet)
		{
			return GetWrapper(hostViewOfContract).Activate(token, process, permissionSet);
		}

		public static object Activate(this AddInToken token, Type hostViewOfContract, AddInSecurityLevel trustLevel, string appDomainName)
		{
			return GetWrapper(hostViewOfContract).Activate(token, trustLevel, appDomainName);
		}

		private static Wrapper GetWrapper(Type contractType)
		{
			if (!wrappers.ContainsKey(contractType))
			{
				wrappers.Add(contractType, new Wrapper(contractType));
			}

			return wrappers[contractType];
		}

		private class Wrapper
		{
			private MethodInfo activate1;
			private MethodInfo activate2;
			private MethodInfo activate3;
			private MethodInfo activate4;
			private MethodInfo activate5;
			private MethodInfo activate6;
			private MethodInfo activate7;

			public Wrapper(Type contractType)
			{
				this.activate1 = activate1def.MakeGenericMethod(contractType);
				this.activate2 = activate2def.MakeGenericMethod(contractType);
				this.activate3 = activate3def.MakeGenericMethod(contractType);
				this.activate4 = activate4def.MakeGenericMethod(contractType);
				this.activate5 = activate5def.MakeGenericMethod(contractType);
				this.activate6 = activate6def.MakeGenericMethod(contractType);
				this.activate7 = activate7def.MakeGenericMethod(contractType);
			}

			public object Activate(AddInToken token, AddInEnvironment environment)
			{
				return this.activate1.Invoke(token, new object[] { environment });
			}

			public object Activate(AddInToken token, AddInSecurityLevel trustLevel)
			{
				return this.activate2.Invoke(token, new object[] { trustLevel });
			}

			public object Activate(AddInToken token, AppDomain target)
			{
				return this.activate3.Invoke(token, new object[] { target });
			}

			public object Activate(AddInToken token, PermissionSet permissions)
			{
				return this.activate4.Invoke(token, new object[] { permissions });
			}

			public object Activate(AddInToken token, AddInProcess process, AddInSecurityLevel level)
			{
				return this.activate5.Invoke(token, new object[] { process, level });
			}

			public object Activate(AddInToken token, AddInProcess process, PermissionSet permissionSet)
			{
				return this.activate6.Invoke(token, new object[] { process, permissionSet });
			}

			public object Activate(AddInToken token, AddInSecurityLevel trustLevel, string appDomainName)
			{
				return this.activate7.Invoke(token, new object[] { trustLevel, appDomainName });
			}
		}
	}
}
